Debugger = require("SharedLibs.Debugger");

--- 是否对异常的操作进行检查，例如在RawCoro下yield一个AsyncOp
_IsStudio = Debugger.IsStudio;


local m = {};

--- 指向Corolib.co对象
_Co = nil;

function m.Init(co)
	_Co = co;
end

local CoroutineHooker = {}

CoroutineHooker.create = coroutine.create;
CoroutineHooker.resume = coroutine.resume;
CoroutineHooker.yield = coroutine.yield;
CoroutineHooker.close = coroutine.close;

CoroutineHooker.running = coroutine.running;
CoroutineHooker.status = coroutine.status;
CoroutineHooker.wrap = coroutine.wrap;
CoroutineHooker.isyieldable = coroutine.isyieldable;

m.RawCoroutine = coroutine;
local _RawYield = coroutine.yield;
local _RawResume = coroutine.resume;

--- 覆盖一部分系统默认coroutine函数
--function CoroutineHooker.resume(co_, ...)
--warn("R: "..tostring(co_));	
--if co_ == co.ErrorCo then
--	warn("R_Stack: "..debug.traceback());
--end

--local state = coroutine.status(co_);
--if state ~= "suspended" then
--	warn(state);
--	assert(false);	
--end
--return _RawResume(co_, ...);
--end

function CoroutineHooker.yield(...)
	local count = select("#", ...);
	if count > 1 then
		--- 超过1个参数，那一定不是Coro里的yield
		return _RawYield(...);
	else
		--- 读取第一个参数（Coro里的yield只有一个参数）
		local obj = ...;
		local objType = type(obj);
		if objType ~= "table" then
			return _RawYield(obj);
		else			
			if _Co.GetCurrent() then
				--- 在_name里放上调试信息
				if _IsStudio and (obj and not obj._name) then
					--- __lvOffset字段用来修正调用深入, 从而打印正确的调试信息
					local lvOffset = 3;
					--local info = debug.getinfo(lvOffset, "Sl")
					local info = debug.getinfo(1, "Sl")
					local fileName = info.short_src
					local line = info.currentline
					--- 找到最后一个.号后的文件名. 这个正则由ChatGPT生成, 可以直接问GPT其含义
					--fileName = string.match(fileName, "%.([^%.]+)$");
					fileName = string.match(fileName, "[^\\/]-%.lua$")
					obj._name = obj._class.name.." - "..fileName..": "..line;
				end
				return _RawYield(obj);
			else
				--- AsyncOp can only be yield in a coroutine!
				if obj.classID == 'IAsyncOp' then
					if Debugger.developMode then
						error("AsyncOp can only be yield in a coroutine! Stack: "
							..debug.traceback());						
					else
						error("AsyncOp can only be yield in a coroutine!");
					end
				end
			end
		end
	end
end	

--[[
	老版本里, 会在g.lua的Init里为所有引用了g.lua的文件Hook. 
	但这导致了对coroutine的普通使用都会出问题(例如把coroutine当generator使用)

	新的设计做了调整: 所有的AsyncOp在文件头部Hook, 这样使用op:Wait()时, 自然是Hook后的, 而不会影响其它使用情况.	
]]
function m.HookCoroutine()
	if _IsStudio then
		--local _old = _ENV["coroutine"];
		_ENV["coroutine"] = CoroutineHooker;
	end
end

m.Yield = CoroutineHooker.yield;

return m;


